// Fill out your copyright notice in the Description page of Project Settings.


#include "Layers/MotionSubtitlesStaticTextLayer.h"
#include "Components/SceneCaptureComponent2D.h"


UMotionSubtitlesStaticTextLayer::UMotionSubtitlesStaticTextLayer()
{
	PrimaryComponentTick.bCanEverTick = true;

	// TODO 确认是否用正交？
	SceneCaptureComponent2D->ProjectionType = ECameraProjectionMode::Perspective;
	SceneCaptureComponent2D->ShowFlags.TemporalAA = true;
	SceneCaptureComponent2D->ShowFlags.PostProcessing = true;
	SceneCaptureComponent2D->SetRelativeLocation(FVector(-500, 0, 0));
}

void UMotionSubtitlesStaticTextLayer::Init(const FUint32Vector2& ViewSize)
{
	Super::Init(ViewSize);
}

void UMotionSubtitlesStaticTextLayer::Show(const FSubtitleParams& Params)
{
	Super::Show(Params);

	Hide();

	for (int32 i = 0; i < TextMeshes.Num(); i++)
	{
		UStaticMeshComponent* StaticMeshComponent;
		if (!GenerateTextMesh(TextMeshes[i], StaticMeshComponent))
		{
			continue;
		}
		SceneCaptureComponent2D->ShowOnlyComponent(StaticMeshComponent);
		TextPlanes.Add(StaticMeshComponent);
	}

	LayoutText(TextPlanes, TextLayoutInfo);
}

void UMotionSubtitlesStaticTextLayer::Hide()
{
	Super::Hide();

	if (TextPlanes.Num() == 0)
	{
		return;
	}

	for (int32 i = 0; i < TextPlanes.Num(); i++)
	{
		SceneCaptureComponent2D->RemoveShowOnlyComponent(TextPlanes[i]);
		TextPlanes[i]->DestroyComponent();
	}
	TextPlanes.Empty();
}

void UMotionSubtitlesStaticTextLayer::Exit()
{
	Super::Exit();
}

void UMotionSubtitlesStaticTextLayer::DoScale(const EAnimTarget AnimTarget, const int32 ElementId, const float Value)
{
	if (AnimTarget == EAnimTarget::WholeLayer)
	{
		if (TextMeshRoot != nullptr)
		{
			TextMeshRoot->SetRelativeScale3D(OriginScale * Value);
		}
	}
	else
	{
		if (TextPlanes.IsValidIndex(ElementId))
		{
			const auto Element = TextPlanes[ElementId];
			Element->SetRelativeScale3D(TextOriginScales[ElementId] * Value);
		}
	}
}

void UMotionSubtitlesStaticTextLayer::DoTranslate(const EAnimTarget AnimTarget, const int32 ElementId,
                                                  const FVector Value)
{
	if (AnimTarget == EAnimTarget::WholeLayer)
	{
		for (int32 i = 0; i < TextPlanes.Num(); i++)
		{
			TextPlanes[i]->SetRelativeLocation(TextOriginLocations[i] + Value);
		}
	}
	else
	{
		if (TextPlanes.IsValidIndex(ElementId))
		{
			const auto Element = TextPlanes[ElementId];
			Element->SetRelativeLocation(TextOriginLocations[ElementId] + Value);
		}
	}
}

void UMotionSubtitlesStaticTextLayer::DoFade(const EAnimTarget AnimTarget, const int32 ElementId, const float Value)
{
	for (const auto Element : TextPlanes)
	{
		TArray<UMaterialInterface*> Materials = Element->GetMaterials();
		for (const auto Material : Materials)
		{
			if (UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(Material))
			{
				DynamicMaterial->SetScalarParameterValue(TEXT("AlphaFactor"), Value);
			}
		}
	}
}

void UMotionSubtitlesStaticTextLayer::CaptureStatus()
{
	Super::CaptureStatus();

	// 原始缩放的值应该是TextMeshRoot的值
	OriginScale = TextMeshRoot->GetRelativeScale3D();

	// 记录文字初始相对位置
	TextOriginLocations.Empty();
	TextOriginScales.Empty();
	for (int32 i = 0; i < TextPlanes.Num(); i++)
	{
		TextOriginLocations.Add(TextPlanes[i]->GetRelativeLocation());
		TextOriginScales.Add(TextPlanes[i]->GetRelativeScale3D());
	}
}

int32 UMotionSubtitlesStaticTextLayer::ElementCount()
{
	return TextPlanes.Num();
}

bool UMotionSubtitlesStaticTextLayer::GenerateTextMesh(UStaticMesh* StaticMesh,
                                                       UStaticMeshComponent*& StaticMeshComponent)
{
	if (StaticMesh == nullptr)
	{
		return false;
	}

	if (TextMeshRoot == nullptr)
	{
		TextMeshRoot = NewObject<USceneComponent>(this,TEXT("TextMeshRoot"));
		TextMeshRoot->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
		TextMeshRoot->RegisterComponent();
	}

	StaticMeshComponent = NewObject<UStaticMeshComponent>(TextMeshRoot);
	StaticMeshComponent->AttachToComponent(TextMeshRoot, FAttachmentTransformRules::KeepRelativeTransform);
	StaticMeshComponent->RegisterComponent();
	StaticMeshComponent->bCastStaticShadow = false;
	StaticMeshComponent->bCastDynamicShadow = false;
	StaticMeshComponent->bVisibleInSceneCaptureOnly = true;
	StaticMeshComponent->SetHiddenInSceneCapture(false);
	StaticMeshComponent->SetStaticMesh(StaticMesh);
	return true;
}

void UMotionSubtitlesStaticTextLayer::LayoutText(TArray<TObjectPtr<UStaticMeshComponent>>& Planes,
                                                 const FTextLayoutInfo& LayoutInfo)
{
	if (Planes.Num() == 0)
	{
		return;
	}

	// 计算每个字符的平均尺寸
	float Average = 0;
	const float Ratio = 1.0f / Planes.Num();
	for (int32 i = 0; i < Planes.Num(); i++)
	{
		const UStaticMesh* StaticMesh = Planes[i]->GetStaticMesh();
		const FBox Box = StaticMesh->GetBoundingBox();
		if (LayoutInfo.Mode == ELayoutMode::Horizontal)
		{
			Average += (Box.GetSize().X) * Ratio;
		}
		else
		{
			Average += (Box.GetSize().Z) * Ratio;
		}
	}

	//  计算布局位置
	// 文字间隔定位文字平均宽度的1/2
	const float Space = Average + (Average * 0.5f * LayoutInfo.KerningScale);
	for (int32 i = 0; i < Planes.Num(); i++)
	{
		const float Value = i * Space - (Planes.Num() - 1) * Space / 2;
		FVector NewLocation;
		if (LayoutInfo.Mode == ELayoutMode::Horizontal)
		{
			NewLocation = FVector(0, Value, 0);
		}
		else
		{
			NewLocation = FVector(0, 0, Value);
		}

		// 设置相对位置
		Planes[i]->SetRelativeLocation(NewLocation);

		// 临时方案，后续需要约定模型的朝向
		Planes[i]->SetRelativeRotation(FRotator(0, 90, 0));
	}
}
